#include "../interface/C_gl_Actor.h"

#include "../cuCommon/cuTypes.h"

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

void C_gl_Actor::Render(I_api_Device * pDevice, C_Camera * pCamera)
{
	matrix4x4 view, projection;

	Matrix4x4LookAtLHR(&view, pCamera->Eye(), pCamera->At(), pCamera->Up());
	Matrix4x4PerspectiveFovGLR(&projection, pCamera->FoV(), pCamera->Asp(), pCamera->zN(), pCamera->zF());

	pDevice->SetProgram(m_pProgram);

	m_pProgram->GetVariableByName("model")->AsMatrix()->SetMatrix((float *)m_pWS);
	m_pProgram->GetVariableByName("view")->AsMatrix()->SetMatrix((float *) &view);
	m_pProgram->GetVariableByName("projection")->AsMatrix()->SetMatrix((float *)&projection);

	uchar4 diffuse = ((T_gl_BaseMaterial<uchar4, uchar> *) m_pBaseMaterial)->diffuse();
	float4 f4diffuse = f4_norm(diffuse);

	m_pProgram->GetVariableByName("diffuse")->AsVector()->SetFloatVector((float *)&f4diffuse);

	if (m_pAsset->m_pPos->Size())
	{
		int vbo = *((int*)((C_gl_Buffer*)m_pAsset->m_pPos->bufferPtr())->Get());
		int offset = m_pAsset->m_pPos->Offset();

		if (vbo)
		{   
			glEnableClientState( GL_VERTEX_ARRAY );
			glBindBufferARB( GL_ARRAY_BUFFER_ARB, vbo );
			glVertexPointer( 3, GL_FLOAT, sizeof(float4), BUFFER_OFFSET(offset*sizeof(float4))); // Set The Vertex Pointer To The Vertex Buffer
		} 
	}

	if (m_pAsset->m_pNml->Size())
	{
		int vbo = *(int*)((C_gl_Buffer*)m_pAsset->m_pNml->bufferPtr())->Get();
		int offset = m_pAsset->m_pNml->Offset();

		if (vbo)
		{
			glEnableClientState( GL_NORMAL_ARRAY );
			glBindBufferARB( GL_ARRAY_BUFFER_ARB, vbo );
			glNormalPointer( GL_FLOAT, sizeof(float4), BUFFER_OFFSET(offset*sizeof(float4)));           // normals are stored in float4 instead of float3
		}
	}

	if (m_pAsset->m_pPosIdx->Size())
	{
		int vbo =  *(int*)((C_gl_Buffer*)m_pAsset->m_pPosIdx->bufferPtr())->Get();
		int offset = m_pAsset->m_pPosIdx->Offset();

		if (vbo)
		{	
			glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, vbo ); 
			glDrawElements(GL_TRIANGLES, m_pAsset->m_pPosIdx->Size(), GL_UNSIGNED_INT, BUFFER_OFFSET(offset*sizeof(int)) ); 
		}
	}

	if (m_pAsset->m_pNml->Size())
		glDisableClientState( GL_NORMAL_ARRAY ); 

	if (m_pAsset->m_pPos->Size())
		glDisableClientState( GL_VERTEX_ARRAY ); 
}

void C_gl_Actor::RenderBVHTree(I_api_Device * pDevice, C_Camera * pCamera, int nMaxLevel)
{
	matrix4x4 view, projection;

	Matrix4x4LookAtLHR(&view, pCamera->Eye(), pCamera->At(), pCamera->Up());
	Matrix4x4PerspectiveFovGLR(&projection, pCamera->FoV(), pCamera->Asp(), pCamera->zN(), pCamera->zF());

	m_pAsset->m_pTree->RenderBVHTree(nMaxLevel, m_pWS, &view, &projection, pDevice);
}